home *** CD-ROM | disk | FTP | other *** search
/ Scene Storm / Scene Storm - Volume 1.iso / coding / c / fp_adpcm / playadpcm / source / playadpcm.c < prev   
C/C++ Source or Header  |  1995-08-25  |  13KB  |  547 lines

  1.  
  2. /* Stand-Alone Player for ADPCM audio samples */
  3. /* Written in 1995 by Christian Buchner. This is Public Domain. */
  4. /* Also look out for xPlay, also available on AmiNet */
  5.  
  6. /* Note: TAB SIZE = 4 */
  7.  
  8. /* Includes */
  9.  
  10. #include <clib/dos_protos.h>
  11. #include <clib/exec_protos.h>
  12. #include <clib/alib_protos.h>
  13. #include <pragmas/dos_pragmas.h>
  14. #include <pragmas/exec_pragmas.h>
  15.  
  16. #include <libraries/dos.h>
  17. #include <dos/rdargs.h>
  18. #include <utility/tagitem.h>
  19. #include <devices/audio.h>
  20. #include <exec/execbase.h>
  21. #include <exec/memory.h>
  22. #include <string.h>
  23. #include <hardware/cia.h>
  24.  
  25.  
  26. /* Prototypes */
  27.  
  28. BOOL PlayADPCM(struct MyVars *mv, UBYTE *Filename, ULONG Size, ULONG Filter, ULONG NoFilter, ULONG Quiet);
  29. BOOL OpenAudio(struct MyVars *mv, ULONG Filter, ULONG NoFilter);
  30. void CloseAudio(struct MyVars *mv);
  31. void AbortPlay(struct MyVars *mv);
  32. void WaitPlay(struct MyVars *mv);
  33.  
  34.  
  35. extern __asm ULONG DecompressADPCM2(    register __a0 UBYTE *Source,
  36.                                         register __d0 ULONG Length,
  37.                                         register __a1 UBYTE *Destination,
  38.                                         register __d1 ULONG JoinCode    );
  39.  
  40. extern __asm ULONG DecompressADPCM3(    register __a0 UBYTE *Source,
  41.                                         register __d0 ULONG Length,
  42.                                         register __a1 UBYTE *Destination,
  43.                                         register __d1 ULONG JoinCode    );
  44.  
  45.  
  46. /* Replay Buffer size */
  47.  
  48. #define CHIP_SIZE 16384
  49.  
  50.  
  51. /* CLI Arguments */
  52.  
  53. UBYTE Template[]="FILES/M/A,ALL/S,FL=FILTER/S,NFL=NOFILTER/S,QUIET/S";
  54.  
  55. struct ArgArray
  56. {
  57.     UBYTE **aa_Files;
  58.     ULONG aa_All;
  59.     ULONG aa_Filter;
  60.     ULONG aa_NoFilter;
  61.     ULONG aa_Quiet;
  62. };
  63.  
  64.  
  65. /* Library Bases */
  66.  
  67. struct DosLibrary *DOSBase;
  68.  
  69.  
  70. /* Local Variables */
  71.  
  72. struct MyVars
  73. {
  74.     struct Process *MyProc;
  75.     
  76.     struct MsgPort *LeftReply[2];
  77.     struct MsgPort *RightReply[2];
  78.     struct IOAudio *LeftAudio[2];
  79.     struct IOAudio *RightAudio[2];
  80.     
  81.     BOOL Playing;
  82.     
  83.     UBYTE *ChipBuffer[2];
  84.     
  85.     BOOL BufPlaying[2];
  86. };
  87.  
  88.  
  89. /* Access to CIA registers */
  90.  
  91. struct CIA *ciaa=(struct CIA*)0xbfe001;
  92.  
  93.  
  94. /* CLI interface and Pattern Matching */
  95.  
  96. LONG __saveds main(void)
  97. {
  98.     struct MyVars *mv;
  99.     UBYTE ProgName[60];
  100.     struct RDArgs *RDArgs;
  101.     struct ArgArray AA={NULL,FALSE,FALSE,FALSE,FALSE};
  102.     char **Files;
  103.     struct AnchorPath *AnchorPath;
  104.     ULONG ReturnCode=RETURN_FAIL;
  105.     
  106.     if (mv=AllocVec(sizeof(struct MyVars),MEMF_ANY|MEMF_CLEAR))
  107.     {
  108.         if (DOSBase=(struct DosLibrary*)OpenLibrary("dos.library",37))
  109.         {
  110.             if (!GetProgramName(ProgName,sizeof(ProgName))) strcpy(ProgName,"PlayADPCM");
  111.             
  112.             if (!(RDArgs=ReadArgs(Template,(LONG *)&AA,0)))
  113.             {
  114.                 PrintFault(IoErr(),ProgName);
  115.             }
  116.             else
  117.             {
  118.                 if (Files=AA.aa_Files)
  119.                 {
  120.                     if (!(AnchorPath=(struct AnchorPath *)AllocVec(sizeof(struct AnchorPath)+256,MEMF_PUBLIC|MEMF_CLEAR)))
  121.                     {
  122.                         PrintFault(ERROR_NO_FREE_STORE,ProgName);
  123.                     }
  124.                     else
  125.                     {
  126.                         ReturnCode=RETURN_OK;
  127.                         
  128.                         AnchorPath->ap_BreakBits=SIGBREAKF_CTRL_C;
  129.                         AnchorPath->ap_Strlen=256;
  130.                         
  131.                         while ((!ReturnCode) && *Files)
  132.                         {
  133.                             LONG RetVal;
  134.                             
  135.                             RetVal=MatchFirst(*Files,AnchorPath);
  136.                             while(!RetVal)
  137.                             {
  138.                                 if (AnchorPath->ap_Info.fib_DirEntryType>0L)
  139.                                 {
  140.                                     if ((!(AnchorPath->ap_Flags&APF_DIDDIR))&&AA.aa_All)
  141.                                     {
  142.                                         AnchorPath->ap_Flags|=APF_DODIR;
  143.                                     }
  144.                                     AnchorPath->ap_Flags&=~APF_DIDDIR;
  145.                                 }
  146.                                 else
  147.                                 {
  148.                                     if (PlayADPCM(mv, AnchorPath->ap_Buf, AnchorPath->ap_Info.fib_Size, AA.aa_Filter, AA.aa_NoFilter, AA.aa_Quiet))
  149.                                     {
  150.                                         RetVal=ERROR_BREAK;
  151.                                         break;
  152.                                     }
  153.                                 }
  154.                                 RetVal=MatchNext(AnchorPath);
  155.                             }
  156.                             MatchEnd(AnchorPath);
  157.                             
  158.                             if (RetVal==ERROR_BREAK)
  159.                             {
  160.                                 PrintFault(RetVal,NULL);
  161.                                 ReturnCode=RETURN_WARN;
  162.                             }
  163.                             else
  164.                             {
  165.                                 if (RetVal!=ERROR_NO_MORE_ENTRIES)
  166.                                 {
  167.                                     PrintFault(RetVal,*Files);
  168.                                     ReturnCode=RETURN_ERROR;
  169.                                 }
  170.                             }
  171.                             Files++;
  172.                         }
  173.                         FreeVec((APTR)AnchorPath);
  174.                     }
  175.                 }
  176.                 FreeArgs(RDArgs);
  177.             }
  178.             CloseLibrary((struct Library*)DOSBase);
  179.         }
  180.         FreeVec(mv);
  181.     }
  182. }
  183.  
  184.  
  185. /* The primitive sample header */
  186.  
  187. struct ADPCMHeader
  188. {
  189.     UBYTE Identifier[6];
  190.     ULONG Frequency;
  191. };
  192.  
  193.  
  194. /* The playback routine */
  195.  
  196. BOOL PlayADPCM(struct MyVars *mv, UBYTE *Filename, ULONG Size, ULONG Filter, ULONG NoFilter, ULONG Quiet)
  197. {
  198.     BOOL Break=FALSE;
  199.     
  200.     BPTR File;
  201.     struct ADPCMHeader ADPCMHeader;
  202.     
  203.     if (!(File=Open(Filename,MODE_OLDFILE)))
  204.     {
  205.         PrintFault(IoErr(),Filename);
  206.     }
  207.     else
  208.     {
  209.         /* Read in sample header */
  210.         if (Read(File,&ADPCMHeader,sizeof(struct ADPCMHeader))==sizeof(struct ADPCMHeader))
  211.         {
  212.             if (strncmp("ADPCM",ADPCMHeader.Identifier,5))
  213.             {
  214.                 Printf("%s: Not ADPCM format!\n",Filename);
  215.             }
  216.             else
  217.             {
  218.                 Size-=sizeof(ADPCMHeader);
  219.                 
  220.                 /* Check if it is a supported ADPCM format */
  221.                 if (ADPCMHeader.Identifier[5] != '2' && ADPCMHeader.Identifier[5] != '3')
  222.                 {
  223.                     Printf("%s: Unsupported ADPCM format!\n",Filename);
  224.                 }
  225.                 else
  226.                 {
  227.                     ULONG Bits;
  228.                     
  229.                     /* Retrieve the number of compression bits */
  230.                     if (ADPCMHeader.Identifier[5] == '2') Bits=2;
  231.                     if (ADPCMHeader.Identifier[5] == '3') Bits=3;
  232.                     
  233.                     if (!OpenAudio(mv,Filter,NoFilter))
  234.                     {
  235.                         Printf("%s: Can't get audio channels!\n",Filename);
  236.                     }
  237.                     else
  238.                     {
  239.                         UBYTE *ADPCMBuffer;
  240.                         ULONG ADPCMSize;
  241.                         
  242.                         if (Bits==2) ADPCMSize=(CHIP_SIZE+3)/4;
  243.                         if (Bits==3) ADPCMSize=(CHIP_SIZE+7)/8*3;
  244.                         
  245.                         if (!(ADPCMBuffer=AllocVec(ADPCMSize, MEMF_ANY|MEMF_CLEAR)))
  246.                         {
  247.                             Printf("%s: Out of memory!\n",Filename);
  248.                         }
  249.                         else
  250.                         {
  251.                             struct Process *MyProc;
  252.                             ULONG Position=0;
  253.                             ULONG JoinCode=0;
  254.                             BOOL ProcActive=TRUE;
  255.                             ULONG Signals;
  256.                             UWORD i;
  257.                             LONG ChipMax, Left, Do, DMALen;
  258.                             BOOL Aborted=FALSE;
  259.                             
  260.                             if (!Quiet) Printf("\rPlaying %s",Filename);
  261.                             
  262.                             MyProc=(struct Process*)FindTask(NULL);
  263.                             
  264.                             Signal(MyProc,(1L<<mv->LeftReply[0]->mp_SigBit));
  265.                             Signal(MyProc,(1L<<mv->LeftReply[1]->mp_SigBit));
  266.                             
  267.                             while(ProcActive)
  268.                             {
  269.                                 ULONG SigMask = SIGBREAKF_CTRL_C |
  270.                                                 (1L<<mv->LeftReply[0]->mp_SigBit) | 
  271.                                                 (1L<<mv->LeftReply[1]->mp_SigBit) ;
  272.                                 
  273.                                 Signals=Wait(SigMask);
  274.                                 
  275.                                 if (Signals & SIGBREAKF_CTRL_C)
  276.                                 {
  277.                                     Printf("\n");
  278.                                     
  279.                                     AbortPlay(mv);
  280.                                     
  281.                                     Break=TRUE;
  282.                                     Aborted=TRUE;
  283.                                     ProcActive=FALSE;
  284.                                 }
  285.                                 
  286.                                 for (i=0;ProcActive && i<2;i++)
  287.                                 {
  288.                                     if (Signals & (1L<<mv->LeftReply[i]->mp_SigBit))
  289.                                     {
  290.                                         if (mv->BufPlaying[i])
  291.                                         {
  292.                                             WaitPort(mv->LeftReply[i]);        GetMsg(mv->LeftReply[i]);
  293.                                             WaitPort(mv->RightReply[i]);    GetMsg(mv->RightReply[i]);
  294.                                             mv->BufPlaying[i]=FALSE;
  295.                                         }
  296.                                         
  297.                                         if (Bits==2) ChipMax = (CHIP_SIZE+3)/4;
  298.                                         if (Bits==3) ChipMax = (CHIP_SIZE+7)/8*3;
  299.                                         
  300.                                         if (Position>=Size)
  301.                                         {
  302.                                             Position=0;
  303.                                             
  304.                                             ProcActive=FALSE;
  305.                                             break;
  306.                                         }
  307.                                         
  308.                                         Left = Size-Position;
  309.                                         Do = Left < ChipMax ? Left : ChipMax;
  310.                                         
  311.                                         if (Do>0)
  312.                                         {
  313.                                             LONG Got;
  314.                                             
  315.                                             if (!Quiet) Printf("\rPlaying %s (%02ld%%)",Filename,100*Position/Size);
  316.                                             
  317.                                             if (Got=Read(File, ADPCMBuffer, Do) != Do)
  318.                                             {
  319.                                                 if (Got<0) PrintFault(IoErr(),Filename);
  320.                                                 else Printf("\r%s: Error, short read!\n",Filename);
  321.                                                 Aborted=TRUE;
  322.                                                 ProcActive=FALSE;
  323.                                                 break;
  324.                                             }
  325.                                             
  326.                                             if (Bits==2) JoinCode=DecompressADPCM2(ADPCMBuffer, Do, mv->ChipBuffer[i], JoinCode);
  327.                                             if (Bits==3) JoinCode=DecompressADPCM3(ADPCMBuffer, Do, mv->ChipBuffer[i], JoinCode);
  328.                                             
  329.                                             Position+=Do;
  330.                                             
  331.                                             if (Bits==2) DMALen = Do*4;
  332.                                             if (Bits==3) DMALen = Do*8/3;
  333.                                             
  334.                                             mv->LeftAudio[i]->ioa_Data =
  335.                                             mv->RightAudio[i]->ioa_Data = mv->ChipBuffer[i];
  336.                                             
  337.                                             mv->LeftAudio[i]->ioa_Length =
  338.                                             mv->RightAudio[i]->ioa_Length = DMALen;
  339.                                             
  340.                                             mv->LeftAudio[i]->ioa_Period = 
  341.                                             mv->RightAudio[i]->ioa_Period=(*(struct ExecBase**)(4))->ex_EClockFrequency*5/ADPCMHeader.Frequency;
  342.                                             
  343.                                             mv->LeftAudio[i]->ioa_Volume=64;
  344.                                             mv->RightAudio[i]->ioa_Volume=64;
  345.                                             
  346.                                             mv->LeftAudio[i]->ioa_Cycles=
  347.                                             mv->RightAudio[i]->ioa_Cycles=1;
  348.                                             
  349.                                             mv->LeftAudio[i]->ioa_Request.io_Flags|=ADIOF_PERVOL;
  350.                                             mv->RightAudio[i]->ioa_Request.io_Flags|=ADIOF_PERVOL;
  351.                                             
  352.                                             mv->LeftAudio[i]->ioa_Request.io_Command=
  353.                                             mv->RightAudio[i]->ioa_Request.io_Command=CMD_WRITE;
  354.                                             
  355.                                             Forbid();
  356.                                             BeginIO(mv->LeftAudio[i]);
  357.                                             BeginIO(mv->RightAudio[i]);
  358.                                             mv->BufPlaying[i]=TRUE;
  359.                                             Permit();
  360.                                         }
  361.                                     }
  362.                                 }
  363.                             }
  364.                             
  365.                             WaitPlay(mv);
  366.                             
  367.                             if ((!Quiet) && (!Aborted)) Printf("\rPlayed  %s - OK \n",Filename);
  368.                             
  369.                             FreeVec(ADPCMBuffer);
  370.                         }
  371.                         CloseAudio(mv);
  372.                     }
  373.                 }
  374.             }
  375.         }
  376.         Close(File);
  377.     }
  378.     return(Break);
  379. }
  380.  
  381.  
  382. /* Allocate audio channels */
  383.  
  384. BOOL OpenAudio(struct MyVars *mv, ULONG Filter, ULONG NoFilter)
  385. {
  386.     BOOL Success=FALSE;
  387.     UWORD i;
  388.     
  389.     UBYTE LeftArray[2]={1,8};
  390.     UBYTE RightArray[2]={2,4};
  391.     
  392.     for (i=0;i<2;i++)
  393.     {
  394.         if (!(mv->LeftReply[i]=CreateMsgPort())) break;
  395.         if (!(mv->RightReply[i]=CreateMsgPort())) break;
  396.         
  397.         if (!(mv->LeftAudio[i]=CreateIORequest(mv->LeftReply[i],sizeof(struct IOAudio)))) break;
  398.         if (!(mv->RightAudio[i]=CreateIORequest(mv->RightReply[i],sizeof(struct IOAudio)))) break;
  399.         
  400.         if (!(mv->ChipBuffer[i]=AllocVec(CHIP_SIZE,MEMF_CHIP))) break;
  401.     }
  402.     if (i==2)
  403.     {
  404.         mv->LeftAudio[0]->ioa_Request.io_Message.mn_Node.ln_Pri=0;
  405.         mv->LeftAudio[0]->ioa_Length=sizeof(LeftArray);
  406.         mv->LeftAudio[0]->ioa_Data=LeftArray;
  407.         mv->LeftAudio[0]->ioa_Request.io_Flags|=ADIOF_NOWAIT;
  408.         if (!OpenDevice("audio.device",0L,(struct IORequest *)mv->LeftAudio[0],0))
  409.         {
  410.             mv->LeftAudio[1]->ioa_Request.io_Device=mv->LeftAudio[0]->ioa_Request.io_Device;
  411.             mv->LeftAudio[1]->ioa_Request.io_Unit=mv->LeftAudio[0]->ioa_Request.io_Unit;
  412.             mv->LeftAudio[1]->ioa_AllocKey=mv->LeftAudio[0]->ioa_AllocKey;
  413.             
  414.             mv->RightAudio[0]->ioa_Length=sizeof(RightArray);
  415.             mv->RightAudio[0]->ioa_Request.io_Message.mn_Node.ln_Pri=0;
  416.             mv->RightAudio[0]->ioa_Data=RightArray;
  417.             mv->RightAudio[0]->ioa_Request.io_Flags|=ADIOF_NOWAIT;
  418.             if (!OpenDevice("audio.device",0L,(struct IORequest *)mv->RightAudio[0],0))
  419.             {
  420.                 mv->RightAudio[1]->ioa_Request.io_Device=mv->RightAudio[0]->ioa_Request.io_Device;
  421.                 mv->RightAudio[1]->ioa_Request.io_Unit=mv->RightAudio[0]->ioa_Request.io_Unit;
  422.                 mv->RightAudio[1]->ioa_AllocKey=mv->RightAudio[0]->ioa_AllocKey;
  423.                 
  424.                 mv->BufPlaying[0]=mv->BufPlaying[1]=FALSE;
  425.                 
  426.                 if (Filter)
  427.                 {
  428.                     ciaa->ciapra &= ~(CIAF_LED);
  429.                 }
  430.                 if (NoFilter)
  431.                 {
  432.                     ciaa->ciapra |= CIAF_LED;
  433.                 }
  434.                 
  435.                 Success=TRUE;
  436.             }
  437.         }
  438.     }
  439.     
  440.     if (!Success)
  441.     {
  442.         CloseAudio(mv);
  443.     }
  444.     
  445.     return(Success);
  446. }
  447.  
  448.  
  449. /* Abort playing */
  450.  
  451. void AbortPlay(struct MyVars *mv)
  452. {
  453.     WORD i;
  454.     
  455.     for (i=0;i<2;i++)
  456.     {
  457.         if (mv->BufPlaying[i])
  458.         {
  459.             AbortIO(mv->LeftAudio[i]);
  460.             AbortIO(mv->RightAudio[i]);
  461.         }
  462.     }
  463.     
  464.     WaitPlay(mv);
  465. }
  466.  
  467.  
  468. /* Wait for audio requests */
  469.  
  470. void WaitPlay(struct MyVars *mv)
  471. {
  472.     WORD i;
  473.     
  474.     for (i=0;i<2;i++)
  475.     {
  476.         if (mv->BufPlaying[i])
  477.         {
  478.             WaitPort(mv->LeftReply[i]);        GetMsg(mv->LeftReply[i]);
  479.             WaitPort(mv->RightReply[i]);    GetMsg(mv->RightReply[i]);
  480.             mv->BufPlaying[i]=FALSE;
  481.         }
  482.     }
  483. }
  484.  
  485.  
  486. /* Close the audio channels */
  487.  
  488. void CloseAudio(struct MyVars *mv)
  489. {
  490.     WORD i;
  491.     
  492.     for (i=0;i<2;i++)
  493.     {
  494.         if (mv->BufPlaying[i])
  495.         {
  496.             AbortIO(mv->LeftAudio[i]);
  497.             AbortIO(mv->RightAudio[i]);
  498.             WaitPort(mv->LeftReply[i]);        GetMsg(mv->LeftReply[i]);
  499.             WaitPort(mv->RightReply[i]);    GetMsg(mv->RightReply[i]);
  500.             mv->BufPlaying[i]=FALSE;
  501.         }
  502.     }
  503.     
  504.     for (i=1;i>=0;i--)
  505.     {
  506.         if (mv->ChipBuffer[i])
  507.         {
  508.             FreeVec(mv->ChipBuffer[i]);
  509.             mv->ChipBuffer[i]=NULL;
  510.         }
  511.         
  512.         if (mv->RightAudio[i])
  513.         {
  514.             if (i==0 && mv->RightAudio[i]->ioa_Request.io_Device)
  515.             {
  516.                 CloseDevice(mv->RightAudio[i]);
  517.                 mv->RightAudio[i]->ioa_Request.io_Device=NULL;
  518.             }
  519.             DeleteIORequest(mv->RightAudio[i]);
  520.             mv->RightAudio[i]=NULL;
  521.         }
  522.         
  523.         if (mv->RightReply[i])
  524.         {
  525.             DeleteMsgPort(mv->RightReply[i]);
  526.             mv->RightReply[i]=NULL;
  527.         }
  528.         
  529.         if (mv->LeftAudio[i])
  530.         {
  531.             if (i==0 && mv->LeftAudio[i]->ioa_Request.io_Device)
  532.             {
  533.                 CloseDevice(mv->LeftAudio[i]);
  534.                 mv->LeftAudio[i]->ioa_Request.io_Device=NULL;
  535.             }
  536.             DeleteIORequest(mv->LeftAudio[i]);
  537.             mv->LeftAudio[i]=NULL;
  538.         }
  539.         
  540.         if (mv->LeftReply[i])
  541.         {
  542.             DeleteMsgPort(mv->LeftReply[i]);
  543.             mv->LeftReply[i]=NULL;
  544.         }
  545.     }
  546. }
  547.